﻿using Gargoyle.Roton;
using System;
using System.Collections.Generic;
using System.Text;

namespace Gargoyle.ZZT
{
    sealed public class ThingCollection : ICollection<Thing>, IEnumerable<Thing>
    {
        public class ThingCollectionEnumerator : IEnumerator<Thing>
        {
            private int baseoffset;
            private int endoffset;
            private Heap heap;
            private Memory memory;
            private int offset;
            private int padding;

            public ThingCollectionEnumerator(Heap heap, Memory memory, int offset, int padding, int capacity)
            {
                this.baseoffset = offset;
                this.endoffset = ((25 + padding) * capacity) + offset;
                this.heap = heap;
                this.memory = memory;
                this.offset = offset;
                this.padding = padding;
            }

            public Thing Current
            {
                get { return new Thing(heap, memory, offset); }
            }

            public void Dispose()
            {
                // not needed
            }

            object System.Collections.IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                offset += 25 + padding;
                return (offset < endoffset);
            }

            public void Reset()
            {
                offset = baseoffset;
            }
        }

        private int capacity;
        private int count = 0;
        private Heap heap;
        private Memory memory;
        private int offset;
        private int padding;

        public ThingCollection(Heap heap, int newCapacity, int padding)
        {
            capacity = newCapacity + 1;
            this.heap = heap;
            this.memory = new Memory(capacity * (25 + padding));
            this.offset = 0;
            this.padding = padding;
        }

        public ThingCollection(Heap heap, int newCapacity, Memory memory, int offset, int padding)
        {
            capacity = newCapacity;
            this.memory = memory;
            this.offset = offset;
            this.padding = padding;
        }

        public Thing this[int index]
        {
            get
            {
                return new Thing(heap, memory, (25 + padding) * index);
            }
            set
            {
                Thing thing = new Thing(heap, memory, (25 + padding) * index);
                thing.CopyFrom(value);
            }
        }

        public void Add(Thing item)
        {
            if (count < capacity)
            {
                this[count] = item;
                count++;
            }
        }

        public int Capacity
        {
            get
            {
                return capacity - 1;
            }
        }

        public int Count
        {
            get
            {
                return count;
            }
        }

        public int IndexOf(Thing item)
        {
            for (int i = 0; i < count; i++)
            {
                if (this[i].Equals(item))
                    return i;
            }
            return -1;
        }

        public bool Remove(Thing item)
        {
            int index = IndexOf(item);

            if (index >= 0)
            {
                RemoveAt(index);
                return true;
            }
            return false;
        }

        public void RemoveAt(int index)
        {
            if (index < count)
            {
                for (int i = 0; i < count; i++)
                {
                    Thing thing = this[i];

                    if (thing.Follower == index)
                        thing.Follower = -1;
                    else if (thing.Follower > index)
                        thing.Follower--;

                    if (thing.Leader == index)
                        thing.Leader = -1;
                    else if (thing.Leader > index)
                        thing.Leader--;
                }

                for (int i = index; i < count - 1; i++)
                {
                    this[i].CopyFrom(this[i + 1]);
                }

                count--;
            }
        }


        public void Clear()
        {
            throw new NotImplementedException();
        }

        public bool Contains(Thing item)
        {
            throw new NotImplementedException();
        }

        public void CopyTo(Thing[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public IEnumerator<Thing> GetEnumerator()
        {
            return new ThingCollectionEnumerator(heap, memory, offset, padding, capacity);
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new ThingCollectionEnumerator(heap, memory, offset, padding, capacity);
        }

        public List<Thing> ToList()
        {
            List<Thing> result = new List<Thing>();

            foreach (Thing entry in this)
            {
                result.Add(entry);
            }

            return result;
        }
    }
}
